#pragma once

// #include "AesEncrypt.h"
#include "HsRequest.h"
#include "Callback.h"
#include "utils.h"

namespace HST3
{
    char s_account[] = "10104064";
    char s_password[] = "111111";
    std::string cust_id;
    std::string client_id;
    char encrypted_password[64]{};
    constexpr char AES_DEFAULT_KEY[] = "1234567812345678";

    Request hsRequest;

    void LoginRequest()
    {
        hsRequest.ClearParam();

        CommonHead head{
            "iic.getAuthuserPasswordLoginExt", "hsxone.iic", cust_id};

        if (Encode3(s_account, '2', '0', s_password, encrypted_password) != 0)
        {
            fmt::print("Encode failed..\n");
            return;
        }

        Security secu;
        secu.pwd_auth_shadow = encrypted_password;
        secu.pwd_auth_type = "2";

        hsRequest.SetHead(head, secu);

        hsRequest.AddParam("auth_id", s_account);
        hsRequest.AddParam("auth_type", "2");

        // ct_key 对应 token_info
        hsRequest.AddParam("ct_key", AES_DEFAULT_KEY);

        // 加密密码
        //  tips: aes128 、AES_cbc_encrypt、 md5_2、 base64
        //  std::string passwd = Encrypt(s_password);
        std::string passwd;
        unsigned char md5str[18]{};
        Utils::MD5_2(s_account, md5str);
        Utils::Encode((const char *)md5str, s_password, strlen(s_password), &passwd);

        std::string checkPwd;
        Utils::Decode((const char *)md5str, passwd.c_str(), passwd.length(), &checkPwd);
        fmt::print("After decode : {}\n", checkPwd);

        hsRequest.AddParam("trade_password", passwd);
        // hsRequest.AddParam("trade_password", s_password);
        hsRequest.AddParam("encode_type", "0");

        // terminal_id
        hsRequest.AddParam("terminal_id", "HD");
        hsRequest.AddParam("terminal_kind", "1");
        hsRequest.AddParam("client_id", " ");
        hsRequest.AddParam("op_entrust_way", "7");
        hsRequest.AddParam("op_station", "HDTEST");

        hsRequest.EndAddParam();
    }

    void QueryFundAccount()
    {
        hsRequest.ClearParam();
        CommonHead head{"act.getFundaccountExt", "hsbroker.act", cust_id};

        Security secu;
        secu.pwd_auth_shadow = encrypted_password;
        secu.pwd_auth_type = "2";

        hsRequest.SetHead(head, secu);

        hsRequest.AddParam("client_id", client_id);
        hsRequest.AddParam("fund_account", s_account);
        hsRequest.AddParam("op_entrust_way", "7");
        hsRequest.AddParam("op_station", "HDTEST");

        hsRequest.EndAddParam();
    }

    void QueryFund()
    {
        hsRequest.ClearParam();

        // CommonHead head{"opt.getFundrealAssetExt", "hsbroker.opt", cust_id};
        CommonHead head{"ses.getFundrealBalanceExt", "hsbroker.ses", cust_id};

        Security secu;
        secu.pwd_auth_shadow = encrypted_password;
        secu.pwd_auth_type = "2";

        hsRequest.SetHead(head, secu);

        hsRequest.AddParam("money_type", "0");
        hsRequest.AddParam("client_id", client_id);
        // hsRequest.AddParam("fund_account", s_account);
        hsRequest.AddParam("op_entrust_way", "7");
        hsRequest.AddParam("op_station", "HDTEST");

        hsRequest.EndAddParam();
    }

    void QueryPosition()
    {
        hsRequest.ClearParam();

        CommonHead head{
            "opt.getHoldrealqueryExt", "hsbroker.opt", cust_id};

        Security secu;
        secu.pwd_auth_shadow = encrypted_password;
        secu.pwd_auth_type = "2";

        hsRequest.SetHead(head, secu);

        hsRequest.AddParam("exchange_type", "1");
        hsRequest.AddParam("client_id", client_id);
        hsRequest.AddParam("fund_account", s_account);
        hsRequest.AddParam("op_entrust_way", "7");
        hsRequest.AddParam("op_station", "HDTEST");

        hsRequest.EndAddParam();
    }

    void QueryAccounts()
    {
        hsRequest.ClearParam();

        CommonHead head{
            "act.getStockholderInfoQueryExt", "hsbroker.act", cust_id};

        Security secu;
        secu.pwd_auth_shadow = encrypted_password;
        secu.pwd_auth_type = "2";

        hsRequest.SetHead(head, secu);

        // hsRequest.AddParam("exchange_type", "1");
        hsRequest.AddParam("client_id", client_id);
        // hsRequest.AddParam("fund_account", s_account);
        hsRequest.AddParam("op_entrust_way", "7");
        hsRequest.AddParam("op_station", "HDTEST");

        hsRequest.EndAddParam();
    }

    void QueryBank()
    {
        hsRequest.ClearParam();

        CommonHead head{
            "ftc.getBankargExt", "hsbroker.ftc", cust_id};

        Security secu;
        secu.pwd_auth_shadow = encrypted_password;
        secu.pwd_auth_type = "2";

        hsRequest.SetHead(head, secu);

        hsRequest.AddParam("exchange_type", "1");
        // hsRequest.AddParam("client_id", client_id);
        // hsRequest.AddParam("fund_account", s_account);
        hsRequest.AddParam("op_entrust_way", "7");
        hsRequest.AddParam("op_station", "HDTEST");

        hsRequest.EndAddParam();
    }

    static constexpr char s_PushServiceName[] = "hsbroker.mc";
    static constexpr char s_OptionTradePushTopicName[] = "secu.opt.busin_push";
    static constexpr char s_OptionOrderPushTopicName[] = "secu.opt.entrust_update_notice";
    static constexpr int s_SubTimeout = 5000;
    static constexpr char s_SubUser[] = "HDServer";

    class CTopicCallback : public IT3SubCallback
    {
    public:
        unsigned long QueryInterface(const char *iid, IBase **ppv) { return 0U; }
        unsigned long AddRef() { return 0U; }
        unsigned long Release() { return 0U; }

        void OnReceived(IT3Subscriber *lpSub, int subscribeIndex, const void *lpData, int nLength, LPSUBSCRIBE_RECVDATA lpRecvData)
        {
        }

        void OnRecvTickMsg(IT3Subscriber *lpSub, int subscribeIndex, const char *TickMsgInfo)
        {
        }
    };

    IT3Subscriber *m_Subscriber = nullptr;
    void SubscribePush(IT3Connection *conn)
    {
        std::string subUserName = fmt::format("{}_{}", s_SubUser, "Test");
        CTopicCallback *m_PushCb = new CTopicCallback;

        if (m_Subscriber != nullptr)
        {
            m_Subscriber->Release();
            m_Subscriber = nullptr;
        }
        m_Subscriber = conn->NewSubscriberEx(m_PushCb, subUserName.c_str(), s_SubTimeout, s_PushServiceName);
        if (m_Subscriber == nullptr)
        {
            fmt::print("NewSubscriberEx failed..[{}]\n", conn->GetMCLastError());
            return;
        }
        m_Subscriber->AddRef();

        IT3SubParam *subParam = NewSubscribeParam();
        if (subParam == nullptr)
        {
            return;
        }
        subParam->AddRef();

        subParam->ResetFilter();
        subParam->SetFromNow(false); // 不需要补缺
        subParam->SetTopicName(s_OptionTradePushTopicName);

        int m_OptionTradeSubFlag = m_Subscriber->SubscribeTopic(subParam, (unsigned int)s_SubTimeout);
        if (m_OptionTradeSubFlag <= 0)
        {
            fmt::print("SubscribeTopic {} failed. {}\n", s_OptionTradePushTopicName, conn->GetMCLastError());
            return;
        }

        subParam->SetTopicName(s_OptionOrderPushTopicName);

        int m_OptionOrderSubFlag = m_Subscriber->SubscribeTopic(subParam, (unsigned int)s_SubTimeout);
        if (m_OptionOrderSubFlag <= 0)
        {
            fmt::print("SubscribeTopic {} failed. {}\n", s_OptionOrderPushTopicName, conn->GetMCLastError());
            return;
        }

        subParam->Release();
    }

}